boost::less_than_comparable

前言

很多操作符都是可以从其他操作符自动推导出来,例如a != b可以从!(a == b)推导出来,因此原则上只需要定义少量的基本操作符,其他的操作符就可以 通过逻辑组合推导出来。

std::rel::ops

在C++98标准的std::rel_ops中定义了四个模板比较操作符!=、>、<=、>=,只需要为类定义==和<操作符,那么这四个操作符就可以自动实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <assert.h>
#include <boost/logic/tribool.hpp>
#include <boost/logic/tribool_io.hpp>
#include <utility>
class demo_class {
public:
demo_class(int n) : x(n) {
}
private:
int x;
public:
friend bool operator<(const demo_class& lhs, const demo_class& rhs) {
return lhs.x < rhs.x;
}
};
int main() {
demo_class a(10), b(20);
using namespace std::rel_ops; // 打开命名空间
std::cout << (a < b) << std::endl;
std::cout << (b >= a) << std::endl;
return 0;
}

boost.opeartors库

同样地,boost.opeartors库允许用户在自己的类里仅定义少量的操作符(如<)就可以方便的自动生成其他操作符重载。

operators库由多个类组成,分别用来实现不同的运算概念,比如less_than_comparable定义了<系列操作符,left_shiftable定义了<<系列操作符。

  • equality_comparable: 要求提供==,可自动实现!=,相等语义;
  • less_than_comparable:要求提供<,可自动实现>,<=,>=;
  • addable:要求提供+=,自动实现+;
  • subtractable:要求提供-=,可自动实现-;
  • incrementable:要求提供前置++,可自动实现后置++;
  • decrementable:要求提供前置–,可自动实现后置–;
  • equivalent:要求提供<,可自动实现==;

这些概念在库中以同名类的形式提供,用户需要以继承的方式来使用它们,继承的修饰符并不重要(private,public都可以),因为operator库里的类都是空类,没有成员变量和成员函数,仅定义了数个友元操作符函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <assert.h>
#include <boost/operators.hpp>
class Point : public boost::less_than_comparable<Point> {
public:
explicit Point(int a = 0, int b = 0, int c = 0)
: x(a), y(b), z(c) {
}
public:
void print() const {
std::cout << x << "," << y << "," << z << std::endl;
}
public:
friend bool operator<(const Point& l, const Point& r) {
return (l.x * l.x + l.y * l.y + l.z * l.z
< r.x * r.x + r.y * r.y + r.z * r.z);
}
private:
int x, y, z;
};

在上面这段代码中,Point类中仅定义了一个友元operator<函数,其余的>、<=、>=均由less_than_comparable自动生成。

在使用operators库时需要注意,模板类型参数必须是子类本身,,特别是当子类本身也是个模板类的时候,不要错写成子类的模板参数或者子类不带模板参数的名称,否则会造成编译错误。在上面代码中,less_than_comparable的模板类型参数必须是Point类。